import os

import pandas as pd
from sklearn.metrics import roc_curve
from sklearn import metrics
from sklearn.metrics import precision_recall_curve
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from pylab import mpl


UPLOAD_FOLDER = './images/'
# 设置显示中文字体
mpl.rcParams["font.sans-serif"] = ["MicroSoft YaHei"]
# 绘制roc曲线
def show_roc(actual, prob, datatype='train', save_path=None):
    import matplotlib.pyplot as plt
    plt.figure(figsize=(10, 8))
    fpr, tpr, threshold = roc_curve(actual,prob)
    roc_auc = metrics.auc(fpr, tpr)
    plt.title("Receiver Operating Characteristic" + '-' + datatype)
    plt.plot(fpr, tpr, 'b', label='AUC = %.2f' % (roc_auc), linewidth=4)
    plt.legend(loc='lower right')
    plt.plot([0, 1], [0, 1], 'r--', linewidth=4)
    plt.xlim([0, 1])
    plt.ylim([0, 1])
    plt.ylabel("True positive Rate")
    plt.xlabel("False positive Rate")
    if save_path is not None:
        plt.savefig(save_path)  # 保存图表到指定路径
# 绘制ks曲线
def show_ks(actual,prob,title='train', save_path=None):
    '''
    1.prob为模型的概率;
    2.actual为y_test,真实标签
    '''
    import numpy as np
    import matplotlib.pyplot as plt
    fpr,tpr,threshold = roc_curve(actual,prob)
    ks_ary = list(map(lambda x,y:x-y,tpr,fpr))
    ks = np.max(ks_ary)
    y_axis = list(map(lambda x:x*1.0/len(fpr),range(0,len(fpr))))
    fig = plt.figure(figsize=(8,6))
    plt.title("K-S Curve" + '-' + title)
    plt.plot(fpr,y_axis,'b--',linewidth=2,label='fpr')
    plt.plot(tpr,y_axis,'y--',linewidth=2,label='tpr')
    plt.plot(y_axis,ks_ary,'g',linewidth=4,label='KS=%.2f'%(ks))
    plt.legend(loc='lower right')
    plt.plot([0,1],[0,1],'r--',linewidth=4)
    plt.xlim([0,1])
    plt.ylim([0,1])
    if save_path is not None:
        plt.savefig(save_path)  # 保存图表到指定路径
# 绘制损失函数曲线
def loss_curve(model, save_path=None):
    results = model.evals_result_
    # print(results)
    # 计算迭代次数
    iterations = len(results['validation_0']['logloss'])
    # print(iterations)
    # 计算横坐标
    x_axis = range(1, iterations+1)
    # print(x_axis)
    # 开始绘制
    fig, ax = plt.subplots()
    ax.plot(x_axis, results['validation_0']['logloss'], label='Train')
    ax.plot(x_axis, results['validation_1']['logloss'], label='Test')
    ax.legend()
    plt.xlabel('Iterations')
    plt.ylabel('LogLoss')
    plt.title('Loss Function Curve')
    if save_path is not None:
        plt.savefig(save_path)  # 保存图表到指定路径
# 绘制pr曲线
def show_pr(actual,prob,datatype='train', save_path=None):
    import matplotlib.pyplot as plt
    plt.figure(figsize=(10,8))
    precisions, recalls, thresholds = precision_recall_curve(actual, prob)
    f1_scores = (2 * precisions * recalls) / (precisions + recalls)
    best_f1_score = np.max(f1_scores[np.isfinite(f1_scores)])
    plt.title("Precision Recall Curve" + '-' + datatype)
    plt.plot(recalls,precisions,label='f1= %.2f'%(best_f1_score),linewidth=4)
    plt.legend(loc='lower right')
    plt.plot([0,1],[0,1],'r--',linewidth=4)
    plt.xlim([0,1])
    plt.ylim([0,1])
    plt.ylabel("Precision",fontsize=14)
    plt.xlabel("Recall",fontsize=14)
    if save_path is not None:
        plt.savefig(save_path)  # 保存图表到指定路径
# 绘制处理前的相关系数图像
def origin_coor(data,target,save_path=None):
    # 注意：corrwith方法自动排除了'target'列本身，因为它只计算其他列与给定列的相关性
    corr = data.drop(target, axis=1).corrwith(data[target])
    # 获取相关性绝对值最大的前六十个特征及其值
    top_60_features = corr.abs().nlargest(60).index.tolist()
    top_60_corr_values = corr[top_60_features].values  # 获取这些特征的相关性值
    # 绘制条形图
    plt.figure(figsize=(12, 8))
    plt.barh(top_60_features, top_60_corr_values, color='skyblue')  # 水平条形图，从上到下（在图表中从左到右）相关性绝对值依次降低
    plt.xlabel('相关性值')  # x轴标签
    plt.ylabel('特征')  # y轴标签
    plt.title('与目标特征相关性最强的前60个非目标特征')  # 图形标题
    plt.grid(axis='x', linestyle='--')  # 可选：添加x轴网格线
    plt.tight_layout()  # 自动调整子图参数
    if save_path is not None:
        plt.savefig(save_path)  # 保存图表到指定路径
# 绘制处理后的相关性系数图像
def afterProcess_coor(data,target,save_path=None):
    # 计算所有特征与目标特征的相关性
    corr = data.drop(target, axis=1).corrwith(data[target])
    # 获取相关性绝对值最大的前二十个特征及其值
    top_20_features = corr.abs().sort_values(ascending=False).head(20).index
    top_20_corr_values = corr[top_20_features].values
    # 绘制条形图（水平条形图）
    plt.figure(figsize=(10, 8))
    plt.barh(top_20_features, top_20_corr_values, color='skyblue')
    # 添加文本注释，显示每个特征的相关性值
    for i, v in enumerate(top_20_corr_values):
        plt.text(v + 0.01, i, '{:.2f}'.format(v), va='center', fontweight='bold')
        # 设置图表标题和轴标签
    plt.xlabel('相关性')
    plt.ylabel('特征')
    plt.title('与目标特征相关性最强的前二十个特征')
    # 显示网格线（可选）
    plt.grid(axis='x', linestyle='--')
    # 调整布局以避免标签被裁剪
    plt.tight_layout()
    if save_path is not None:
        plt.savefig(save_path)  # 保存图表到指定路径
# 绘制前二十特征的相关性矩阵
def heatMap(data,target,save_path=None):
    # 排除目标特征，计算剩余特征之间的相关性
    # corr_matrix = data.drop(target, axis=1).corr()
    corr_matrix = data.corr()
    # 获取相关性绝对值最大的前二十个特征（不考虑对角线）
    # 注意：这里我们实际上是在寻找与所有其他特征相关性最强的特征，而不仅仅是彼此之间的
    # 但为了简化，我们可以先选取与target相关性最强的前二十个特征
    top_20_features = data.corrwith(data[target]).abs().sort_values(ascending=False).head(20).index
    # 筛选这些特征的相关性矩阵
    top_corr_matrix = corr_matrix.loc[top_20_features, top_20_features]
    # 绘制热图
    plt.figure(figsize=(12, 10))
    sns.heatmap(top_corr_matrix, annot=True, cmap='coolwarm', fmt=".2f")
    # 设置图表标题和轴标签（热图的轴标签可能不是很清晰，因为它们只是特征的索引）
    plt.title('前二十特征之间的相关性矩阵')
    plt.xlabel('特征')
    plt.ylabel('特征')
    if save_path is not None:
        plt.savefig(save_path)  # 保存图表到指定路径

# 绘制医院累计就诊人数
def plot_hospital_visits(dataSet_URL):
    # 使用pandas读取CSV文件
    df = pd.read_csv(dataSet_URL)
    # 假设“医院编码_NN”是医院编码的列名
    if '医院编码_NN' in df.columns:
        # 计算每个医院的病患数量
        hospital_visits = df.groupby('医院编码_NN').size().reset_index(name='病患数量')
        # 绘制折线图
        plt.figure(figsize=(10, 6))
        plt.plot(hospital_visits['医院编码_NN'], hospital_visits['病患数量'], marker='o')
        plt.title('医院病患数量')
        plt.xlabel('医院编码_NN')
        plt.ylabel('病患数量')
        plt.xticks(rotation=45, ha="right")  # 如果医院编码标签太长，可以旋转并调整水平对齐
        # 保存图片到UPLOAD_FOLDER
        plot_path = os.path.join(UPLOAD_FOLDER, 'hospital_visits.png')
        plt.savefig(plot_path)
        plt.close()  # 关闭绘图窗口
        # 返回图片文件的相对路径（这里实际上不需要，因为图片已经保存在了UPLOAD_FOLDER）
        return plot_path

def plot_monthly_visits(dataSet_URL):
    # 使用pandas读取CSV文件
    df = pd.read_csv(dataSet_URL)
    # 假设“就诊的月数”是包含月份信息的列名
    if '就诊的月数' in df.columns:
        # 统计每个月份的病患数量
        monthly_visits = df['就诊的月数'].value_counts().sort_index().reset_index()
        monthly_visits.columns = ['月份', '病患数量']
        # 绘制饼图
        plt.figure(figsize=(8, 8))
        plt.pie(monthly_visits['病患数量'], labels=monthly_visits['月份'], autopct='%1.1f%%', startangle=140)
        plt.title('每月病患数量分布')
        plt.axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle.
        # 保存图片到UPLOAD_FOLDER
        plot_path = os.path.join(UPLOAD_FOLDER, 'monthly_visits.png')
        plt.savefig(plot_path)
        plt.close()  # 关闭绘图窗口
        # 返回图片文件的相对路径（这里实际上不需要，因为图片已经保存在了UPLOAD_FOLDER）
        return plot_path
